﻿using System;

namespace KWatkins.FluentMoqBuilder.Argument
{
	/// <summary>
	/// Validates a signed, precise numeric argument.
	/// </summary>
	/// <typeparam name="T">The numeric type.</typeparam>
	internal interface ISignedPreciseNumber<T>
		where T : struct
	{
		/// <summary>
		/// Validates the argument is greater than some value.
		/// </summary>
		/// <param name="minimum">The minimum value to test against.</param>
		/// <exception cref="ArgumentOutOfRangeException">
		/// If the argument is not greater than <paramref name="minimum" />.
		/// </exception>
		/// <returns>A <see cref="ISignedPreciseNumber{T}" /> to continue validation.</returns>
		ISignedPreciseNumber<T> IsGreaterThan(T minimum);

		/// <summary>
		/// Validates the argument is greater than or equal to some value.
		/// </summary>
		/// <param name="minimum">The minimum value to test against.</param>
		/// <exception cref="ArgumentOutOfRangeException">
		/// If the argument is not greater than or equal to <paramref name="minimum" />.
		/// </exception>
		/// <returns>A <see cref="ISignedPreciseNumber{T}" /> to continue validation.</returns>
		ISignedPreciseNumber<T> IsGreaterThanOrEqualTo(T minimum);

		/// <summary>
		/// Validates the argument is less than some value.
		/// </summary>
		/// <param name="maximum">The maximum value to test against.</param>
		/// <exception cref="ArgumentOutOfRangeException">
		/// If the argument is not less than <paramref name="maximum" />.
		/// </exception>
		/// <returns>A <see cref="ISignedPreciseNumber{T}" /> to continue validation.</returns>
		ISignedPreciseNumber<T> IsLessThan(T maximum);

		/// <summary>
		/// Validates the argument is less than or equal to some value.
		/// </summary>
		/// <param name="maximum">The maximum value to test against.</param>
		/// <exception cref="ArgumentOutOfRangeException">
		/// If the argument is not less than or equal to <paramref name="maximum" />.
		/// </exception>
		/// <returns>A <see cref="ISignedPreciseNumber{T}" /> to continue validation.</returns>
		ISignedPreciseNumber<T> IsLessThanOrEqualTo(T maximum);

		/// <summary>
		/// Validates the argument is positive, i.e. greater than zero.
		/// </summary>
		/// <exception cref="ArgumentOutOfRangeException">
		/// If the argument is not positive.
		/// </exception>
		/// <returns>A <see cref="IUnsignedPreciseNumber{T}" /> to continue validation.</returns>
		IUnsignedPreciseNumber<T> IsPositive();

		/// <summary>
		/// Validates the argument is not positive, i.e. negative or zero.
		/// </summary>
		/// <exception cref="ArgumentOutOfRangeException">
		/// If the argument is positive.
		/// </exception>
		/// <returns>A <see cref="IUnsignedPreciseNumber{T}" /> to continue validation.</returns>
		IUnsignedPreciseNumber<T> IsNotPositive();

		/// <summary>
		/// Validates the argument is negative, i.e. less than zero.
		/// </summary>
		/// <exception cref="ArgumentOutOfRangeException">
		/// If the argument is not negative.
		/// </exception>
		/// <returns>A <see cref="IUnsignedPreciseNumber{T}" /> to continue validation.</returns>
		IUnsignedPreciseNumber<T> IsNegative();

		/// <summary>
		/// Validates the argument is not negative, i.e. positive or zero.
		/// </summary>
		/// <exception cref="ArgumentOutOfRangeException">
		/// If the argument is not negative.
		/// </exception>
		/// <returns>A <see cref="IUnsignedPreciseNumber{T}" /> to continue validation.</returns>
		IUnsignedPreciseNumber<T> IsNotNegative();
	}
}